package com.stormragetech.teamwork.module.user.spring.service.impl;

import com.alibaba.fastjson.JSON;
import com.stormragetech.common.exception.StormragetechException;
import com.stormragetech.common.utils.StormragetechUtils;
import com.stormragetech.teamwork.common.constant.Constants;
import com.stormragetech.teamwork.common.util.AESCrypt;
import com.stormragetech.teamwork.common.util.SecurityUtils;
import com.stormragetech.teamwork.module.user.entity.User;
import com.stormragetech.teamwork.module.user.entity.UserMongo;
import com.stormragetech.teamwork.module.user.model.LoginModel;
import com.stormragetech.teamwork.module.user.model.RegitrationModel;
import com.stormragetech.teamwork.module.user.model.TokenInfoModel;
import com.stormragetech.teamwork.module.user.spring.dao.UserDao;
import com.stormragetech.teamwork.module.user.spring.mongo.UserMongoDao;
import com.stormragetech.teamwork.module.user.spring.redis.RedisDao;
import com.stormragetech.teamwork.module.user.spring.service.UserService;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * description: //TODO
 *
 * @author: Xue Bin
 * @version: 1.0.0-SNAPSHOT
 */
@Log4j2
@Service
public class UserServiceImpl implements UserService {

    @Value("${aeskey}")
    private String aeskey;

    private final RedisDao redisDao;
    private final UserDao userDao;
    private final UserMongoDao userMongoDao;

    @Autowired
    public UserServiceImpl(final RedisDao redisDao, final UserDao userDao, UserMongoDao userMongoDao) {
        Assert.notNull(redisDao, "RedisDao cannot be null !!!");
        Assert.notNull(userDao, "UserDao cannot be null !!!");
        Assert.notNull(userMongoDao, "UserMongoDao cannot be null !!!");
        this.redisDao = redisDao;
        this.userDao = userDao;
        this.userMongoDao = userMongoDao;
    }

    @Override
    public String login(final LoginModel model) throws StormragetechException {

        final Map<String, Object> map = new HashMap<>();
        map.put("username", model.getUsername());

        User user = userDao.queryByName(map);
        if (null == user) {
            throw new StormragetechException(Constants.USER_NOEXIST_CODE, Constants.USER_NOEXIST_MSG);
        }

        String password = SecurityUtils.pass(model.getPassword(), user.getSalt());
        if (!password.equals(user.getPassword())) {
            throw new StormragetechException(Constants.PASS_ERR_CODE, Constants.PASS_ERR_MSG);
        }

        // test
        List<UserMongo> list = userMongoDao.find();
        list.forEach(s -> log.info(s));

        // generate token
        // encrypt token with AES
        //
        String token = genToken(user.getId());
        return AESCrypt.encrypt(token, aeskey);
    }

    @Override
    public String registration(RegitrationModel model) throws StormragetechException {

        // generate password
        //
        String salt = StormragetechUtils.random(1, 8);
        String pass = SecurityUtils.pass(model.getPassword(), salt);

        // generate User entity
        // insert to mysql
        //
        User entity = new User(0, model.getUsername(), pass, salt, model.getRealname(), new Date(), Constants.UNLOCKED);
        int id = userDao.create(entity);

        // generate token
        // encrypt token with AES
        //
        String token = genToken(id);
        return AESCrypt.encrypt(token, aeskey);

    }

    private String genToken(final int id) throws StormragetechException {

        // generate token
        // save to redis
        //
        String token = StormragetechUtils.random(1, 8);

        Map<String, Object> map = new HashMap<>();
        map.put("id", id);
        List<String> sign = userDao.queryPermByUser(map);

        TokenInfoModel info = new TokenInfoModel(id, sign);
        redisDao.setKV(token, JSON.toJSONString(info), Constants.LOGIN_EXPIRE);

        return token;
    }

}
